#include <dspSimulator/targetMachine/sploopbuffer.h>

void SPLoopBuffer::initialWithSPLoop(u32 ii, std::bitset<4> condition) {
    m_spLoopKind = SPLoopKind::SPLoop;
    m_ii = ii;
    m_condition = condition;
    m_buffer.clear();
    m_stageNum.clear();
    m_instState.clear();
}

void SPLoopBuffer::initialWithSPLoopD(u32 ii, std::bitset<4> condition) {
    m_spLoopKind = SPLoopKind::SPLoopD;
    m_ii = ii;
    m_condition = condition;
    m_buffer.clear();
    m_stageNum.clear();
    m_instState.clear();
}

void SPLoopBuffer::initialWithSPLoopW(u32 ii, std::bitset<4> condition) {
    m_spLoopKind = SPLoopKind::SPLoopW;
    m_ii = ii;
    m_condition = condition;
    m_buffer.clear();
    m_stageNum.clear();
    m_instState.clear();
}


void SPLoopBuffer::loadInstruction(std::shared_ptr<DspInstruction> instruction, u32 offset, bool state) {
    m_buffer.push_back(instruction);
    m_stageNum.push_back(m_numOfStage);
    m_offset.push_back(offset);
    m_instState.push_back(state);
}

void SPLoopBuffer::enableSPLoopBuffer() {
    m_spLoopBufferState = SPLoopBufferState::ACTIVE;
}

bool SPLoopBuffer::isActive() {
    return m_spLoopBufferState == SPLoopBufferState::ACTIVE;
}

void SPLoopBuffer::incrementLBC() {
    // 每个周期末，LBC加1
    ++m_LBC[0];
    // 如果LBC == ii,即当前周期中，程序执行到了stage边界
    if (m_LBC[0] == m_ii) {
        // stage数加1
        ++m_numOfStage;
        if (isLoad()) {
            m_numOfLoad += 1;
        }
        if (isFetch()) {
            m_numOfFetch += 1;
        }
        if (isDrain()) {
            m_numOfDrain += 1;
        }
        if (isReload()) {
            m_numOfReload += 1;
        }
        // 到达stage边界，重置LBC为0
        m_LBC[0] = 0;
        // 到达stage边界，如果ILC大于0，ILC减1
        auto ILCRegRead = m_dspMachine->getSaveRegs()->getReg32ByName("ILC");
        auto ILCRegWrite = m_dspMachine->getRegisters()->getReg32ByName("ILC");
        if (*ILCRegRead->getDataPtr() > 0)
            ILCRegWrite->updateData(*ILCRegRead->getDataPtr() - 1);

        checkTerminate();
    }
}

std::vector<std::shared_ptr<DspInstruction>> SPLoopBuffer::fetchInstructions() {
    std::vector<std::shared_ptr<DspInstruction>> dspInstructions;
    // 遍历buffer中的所有指令
    for (u32 i = 0; i < m_buffer.size(); ++i) {
        // 如果当前指令偏移量等于LBC，且当前指令未被屏蔽,该指令将从buffer中取出并执行
        if (m_offset[i] == m_LBC[0] && m_instState[i]) {
            dspInstructions.push_back(m_buffer[i]->clone());
        }
    }
    return dspInstructions;
}

void SPLoopBuffer::setFstgAndFcyc(u32 fstg, u32 fcyc) {
    m_fstg = fstg;
    m_fcyc = fcyc;
}

void SPLoopBuffer::drainOneStage() {
    if (m_buffer.empty())
        return;
    // m_currentDrainIndex始终指向上一次drain的最后一条指令,++使其指向当前需要drain的第一条指令
    ++m_currentDrainIndex;
    // 获取当前需要drain的指令的stage数
    u32 stageNum = m_stageNum[m_currentDrainIndex];
    // 将当前stage的指令的状态全设置为0，表示已废弃
    m_instState[m_currentDrainIndex] = false;
    while (++m_currentDrainIndex) {
        if (m_stageNum[m_currentDrainIndex] != stageNum) {
            --m_currentDrainIndex;
            break;
        }
        m_instState[m_currentDrainIndex] = false;
    }
}

bool SPLoopBuffer::checkCondition() {
    if (m_condition == 0b0000) {
        // Unconditional
        return true;
    } else if (m_condition == 0b0001 || m_condition == 0b1110 || m_condition == 0b1111) {
        return false;
    } else if (m_condition == 0b0010) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("B0")->getDataPtr() != 0;
    } else if (m_condition == 0b0011) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("B0")->getDataPtr() == 0;
    } else if (m_condition == 0b0100) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("B1")->getDataPtr() != 0;
    } else if (m_condition == 0b0101) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("B1")->getDataPtr() == 0;
    } else if (m_condition == 0b0110) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("B2")->getDataPtr() != 0;
    } else if (m_condition == 0b0111) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("B2")->getDataPtr() == 0;
    } else if (m_condition == 0b1000) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("A1")->getDataPtr() != 0;
    } else if (m_condition == 0b1001) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("A1")->getDataPtr() == 0;
    } else if (m_condition == 0b1010) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("A2")->getDataPtr() != 0;
    } else if (m_condition == 0b1011) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("A2")->getDataPtr() == 0;
    } else if (m_condition == 0b1100) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("A0")->getDataPtr() != 0;
    } else if (m_condition == 0b1101) {
        return *m_dspMachine->getSaveRegs()->getReg32ByName("A0")->getDataPtr() == 0;
    } else {
        return true;
    }
}

void SPLoopBuffer::checkTerminate() {
    switch (m_spLoopKind) {
        case SPLoopKind::SPLoop:
        case SPLoopKind::SPLoopD:
            if (*m_dspMachine->getRegisters()->getReg32ByName("ILC")->getDataPtr() == 0)
                m_isTerminate = true;
            break;
        case SPLoopKind::SPLoopW:
            if (!checkCondition())
                m_isTerminate = true;
            break;
        default:
            break;
    }
}

u32 SPLoopBuffer::getDelay() const {
    return m_fstg * m_ii + m_fcyc;
}

bool SPLoopBuffer::isReachBoundary() const {
    return m_ii == m_LBC[0];
}

SPLoopKind SPLoopBuffer::getSPLoopKind() {
    return m_spLoopKind;
}

void SPLoopBuffer::loadExecutePacketIntoBuffer(const std::vector<std::shared_ptr<Instruction>> &executePacket) {
    std::bitset<8> maskBitsets;   //L1 L2 S1 S2 D1 D2 M1 M2        // spmask指令的掩码
    u32 offset;       // 当前指令在当前stage的偏移量

    // 如果当前指令的stage与前一个指令的stage不同，表明当前指令为其所属的stage的第一条指令，偏移量设置为0
    if (m_offset.empty() || m_stageNum[m_stageNum.size() - 1] != m_numOfStage) {
        offset = 0;
    } else {
        // 如果当前指令的stage与前一条指令相同，则偏移量为前一条指令的偏移量加一
        offset = m_offset[m_offset.size() - 1] + 1;
    }

    for (auto &instruction: executePacket) {
        auto dspInstruction = std::dynamic_pointer_cast<DspInstruction>(instruction);
        auto clone = dspInstruction->clone();
        if (dspInstruction->getName() == "SPMASK") {
            // 如果指令类型为spmask指令,设置mask掩码，并且不将spmask指令放入buffer中
            maskBitsets = dspInstruction->spMaskBitset;
            loadInstruction(clone, offset, false);
        } else if (dspInstruction->getName() == "SPKERNEL") {
            // 如果指令为spkernel指令,不将spkernel指令放入buffer中
            loadInstruction(clone, offset, false);
        } else if (dspInstruction->numOfInsertNOP > 0) {
            // 如果指令有多个需要插入在当前执行包之后的nop指令，展开nop，并将nop为0的指令插入到buffer中
            clone->numOfInsertNOP = 0;
            loadInstruction(clone, offset, !isMaskInst(maskBitsets, dspInstruction->funcUnit));
        } else {
            // 无nop插入操作的指令，直接加载到buffer中
            loadInstruction(clone, offset, !isMaskInst(maskBitsets, dspInstruction->funcUnit));
        }
    }
}

bool SPLoopBuffer::isMaskInst(const std::bitset<8> &maskBitset, FuncUnit funcUnit) {
    switch (funcUnit) {
        case FuncUnit::L1:
            return maskBitset[0];
        case FuncUnit::L2:
            return maskBitset[1];
        case FuncUnit::S1:
            return maskBitset[2];
        case FuncUnit::S2:
            return maskBitset[3];
        case FuncUnit::D1:
            return maskBitset[4];
        case FuncUnit::D2:
            return maskBitset[5];
        case FuncUnit::M1:
            return maskBitset[6];
        case FuncUnit::M2:
            return maskBitset[7];
        default:
            return false;
    }
}

void SPLoopBuffer::setLoad(bool flag) {
    if (flag) {
        m_stageKind[0] = true;
    } else {
        m_stageKind[0] = false;
    }
}

void SPLoopBuffer::setFetch(bool flag) {
    if (flag) {
        m_stageKind[1] = true;
    } else {
        m_stageKind[1] = false;
    }
}

void SPLoopBuffer::setDrain(bool flag) {
    if (flag) {
        m_stageKind[2] = true;
    } else {
        m_stageKind[2] = false;
    }
}

void SPLoopBuffer::setReload(bool flag) {
    if (flag) {
        m_stageKind[3] = true;
    } else {
        m_stageKind[3] = false;
    }
}

void SPLoopBuffer::disableSPLoopBuffer() {
    m_spLoopKind = SPLoopKind::UnKnown;
    m_spLoopBufferState = SPLoopBufferState::IDLE;
    m_numOfStage = m_numOfLoad = m_numOfFetch = m_numOfDrain = m_numOfReload = 0;
    m_currentDrainIndex = 0xffffffff;
    m_ii = 0;
    m_LBC[0] = 0;
    m_LBC[1] = 0;
    m_condition.reset();
    m_stageKind.reset();
    m_buffer.clear();
    m_stageNum.clear();
    m_offset.clear();
    m_instState.clear();
    m_fstg = m_fcyc = 0;
    m_isTerminate = false;
}

u32 SPLoopBuffer::getNumOfLoad() const {
    return m_numOfLoad;
}

u32 SPLoopBuffer::getNumOfFetch() const {
    return m_numOfFetch;
}

u32 SPLoopBuffer::getNumOfDrain() const {
    return m_numOfDrain;
}

u32 SPLoopBuffer::getNumOfReload() const {
    return m_numOfReload;
}

void SPLoopBuffer::initial(std::shared_ptr<DspInstruction> sploopInstruction) {
    if (!sploopInstruction) {
        return;
    }
    enableSPLoopBuffer();
    if (sploopInstruction->m_name == "SPLOOP") {
        initialWithSPLoop(sploopInstruction->ii, sploopInstruction->creg_z);
    } else if (sploopInstruction->m_name == "SPLOOPD") {
        initialWithSPLoopD(sploopInstruction->ii, sploopInstruction->creg_z);
    } else if (sploopInstruction->m_name == "SPLOOPW") {
        initialWithSPLoopW(sploopInstruction->ii, sploopInstruction->creg_z);
    }
}

bool SPLoopBuffer::haveFinishDrain() {
    return m_currentDrainIndex == m_buffer.size()-1;
}




